/*
 * Copyright (C), 2018-2019, 深圳联合保理有限公司
 * FileName: JwtUtils
 * Author:   jinjie.chen
 * Date:     2019/9/19 11:04
 * @since 1.0.0
 */
package com.dome.auth.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.dome.util.constans.JWTConstants;
import com.dome.util.redis.RedisKeyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ObjectUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author jinjie.chen
 * 2019/9/19 11:04
 * @since 1.0.0
 */
@Slf4j
public class JwtUtils {

    private static final String SIGN="TEST";

    public static void main(String[] args) {
        Map<String,String> map=new HashMap<>();
        map.put("account","111");
        map.put("sessionId,","eee");
        String token=genToken(map,600);
        System.out.println(token);

        String t="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzZXNzaW9uSWQsIjoiZWVlIiwiZXhwIjoxNjE3NDQyMDE4LCJhY2NvdW50IjoiMTExIn0.MWHD12cJkNPozjyDV-ye4eHdgwHTZTd-qyni1RjNJf0";
        String b=getAccount(t);
        System.out.println(b);
    }

    /**
     * 通过账户和密码生成token
     * @param seconds 过期时间（秒）
     * @return
     */
    public static String genToken(Map<String,String> map, Integer seconds) {
        Calendar calendar=Calendar.getInstance();
        //calendar.add(Calendar.SECOND,seconds);
        calendar.add(Calendar.MINUTE,seconds);
        JWTCreator.Builder builder = JWT.create();
        if(ObjectUtils.isEmpty(map)){
            return builder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(SIGN));
        }
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });
        String token=builder.withExpiresAt(calendar.getTime())
                .sign(Algorithm.HMAC256(SIGN));
        return token;
    }
    /**
     * token是否超时 超时false 未超时ture
     * @param token
     */
    public static Boolean isExpires(String token) {
        if(!verifyToken(token)){
            return false;
        }
        Date  expiresAt  = JWT.decode(token).getExpiresAt();
        if(expiresAt.before(new Date())) {
            //如果超时时间 在当前时间之前 表示已经超时
            return false;
        }
        return true;
    }

    /**
     * 通过token获取redis的key 由account 和sessionid组成
     * 如果redis已经失效 表示对应的sessionid和account组合的用户已经登陆失效
     * @param token
     * @return
     */
    public static String loginRedisKey(String token) {
        if(StringUtils.isEmpty(token)||!verifyToken(token)) {
            return null;
        }
        String account =getAccount(token);
        String sessionId = getSessionId(token);
        String redisKey = RedisKeyUtil.loginRedisKey(account, sessionId);
        return redisKey;
    }

    /**
     * 验证token是否超时以及是否被篡改
     * @param token
     * @return
     */
    public static boolean verifyToken(String token){
        try {
            JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
        }catch (SignatureVerificationException e){
            log.info("Token签名无效");
            return false;
        }catch (TokenExpiredException e){
            log.info("Token超时");
            return false;
        }catch (AlgorithmMismatchException e){
            log.info("Token算法不匹配");
            return false;
        }catch (Exception e){
            log.info("Token异常");
            return false;
        }
        return true;
    }
    public static String getAccount(String token) {
        if(StringUtils.isEmpty(token)||!verifyToken(token)) {
            return null;
        }
        DecodedJWT decodedJWT = JWT.decode(token);
        if(ObjectUtils.isEmpty(decodedJWT.getClaims())){
            return null;
        }
        String  account  = decodedJWT.getClaim(JWTConstants.ACCOUNT).asString();
        return account;
    }

    public static String getSessionId(String token) {
        if(StringUtils.isEmpty(token)||!verifyToken(token)) {
            return null;
        }
        DecodedJWT decodedJWT = JWT.decode(token);
        if(ObjectUtils.isEmpty(decodedJWT.getClaims())){
            return null;
        }
        String  sessionId  = decodedJWT.getClaim(JWTConstants.SESSIONID).asString();
        return sessionId;
    }


}